package com.jiexinyun.ftp;

import com.jiexinyun.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.*;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component
public class FtpUtil {

    @Value("${file.prefix}")
    private String prefixlink;

    private static GenericObjectPool<FTPClient> ftpClientPool;
    private static FtpProperties ftpProperties;

    @Autowired
    public FtpUtil(FtpProperties properties) {
        ftpProperties = properties;
    }

    @PostConstruct
    public void init() {

        GenericObjectPoolConfig<FTPClient> config = new GenericObjectPoolConfig<>();
        config.setMaxTotal(ftpProperties.getPool().getMaxTotal());
        config.setMinIdle(ftpProperties.getPool().getMinIdle());
        config.setMaxIdle(ftpProperties.getPool().getMaxIdle());
        config.setMaxWait(Duration.ofSeconds(ftpProperties.getPool().getMaxWait()));
        FtpClientFactory factory = new FtpClientFactory(
                ftpProperties.getHost(),
                ftpProperties.getPort(),
                ftpProperties.getUsername(),
                ftpProperties.getPassword(),
                ftpProperties.isPassiveMode()
        );

        ftpClientPool = new GenericObjectPool<>(factory, config);
    }

    @PreDestroy
    public void destroy() {
        if (ftpClientPool != null && !ftpClientPool.isClosed()) {
            ftpClientPool.close();
        }
    }

    /**
     * 列出SFTP目录下的文件
     * remotePath 一定要是 /开头的 最末级是目录 而且不以/结尾
     */
    public List<String> listFiles(String remotePath)  {
        FTPClient ftpClient = null;
        List<String> list = new ArrayList<>();
        try {
            ftpClient = ftpClientPool.borrowObject();
            String encodedPath = new String(remotePath.getBytes("GBK"), "ISO-8859-1");

            FTPFile[] files = ftpClient.listFiles(encodedPath);

            log.info("直接列出文件数量: " + files.length);

            for (FTPFile file : files) {
                log.info(file.getName());
                if(file.isDirectory()) {
                    continue;
                }
                // 跳过当前目录(.)和上级目录(..)
                // file跳过目录类型
                list.add(prefixlink+remotePath+"/"+file.getName());
            }
            //list是我最终想要的结果
            log.info("文件列表：" + list);
        } catch (Exception e) {
            log.error("查询文件列表报错：", e);
        }finally {
            if(ftpClient != null) {
                ftpClientPool.returnObject(ftpClient);
            }
        }
        return list;
    }

    private static class FtpClientFactory extends BasePooledObjectFactory<FTPClient> {

        private String host;

        private int port;

        private String username;

        private String password;

        private boolean passiveMode;

        public FtpClientFactory(String host, int port, String username, String password, boolean passiveMode) {
            this.host = host;
            this.port = port;
            this.username = username;
            this.password = password;
            this.passiveMode  = passiveMode ;
        }

        @Override
        public FTPClient create() throws Exception {
            FTPClient ftpClient = new FTPClient();
            try {
                ftpClient.connect(host, port);

                // 2. 登录
                if (!ftpClient.login(username, password)) {
                    throw new IOException("FTP登录失败");
                }

                // 3. 设置被动模式（推荐）
                ftpClient.enterLocalPassiveMode();

                // 4. 设置文件类型（二进制模式防止文件损坏）
                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);

                // 5. 处理中文编码（根据服务器设置）
                ftpClient.setControlEncoding("GBK"); // 或GBK
                // 2. 关键编码设置
                ftpClient.enterLocalPassiveMode();

                return ftpClient;
            } catch (Exception e) {
                log.error("FTPS client creation failed", e);
                if (ftpClient.isConnected()) {
                    ftpClient.disconnect();
                }
                throw e;
            }
        }

        @Override
        public PooledObject<FTPClient> wrap(FTPClient ftpClient) {

            return new DefaultPooledObject<>(ftpClient);
        }

        @Override
        public boolean validateObject(PooledObject<FTPClient> p) {
            if(CommonUtils.isNull(p)) {
                return false;
            }
            FTPClient ftpClient = p.getObject();
            if(CommonUtils.isNull(ftpClient)) {
                return false;
            }
            return ftpClient.isConnected();
        }

        @Override
        public void destroyObject(PooledObject<FTPClient> p) throws Exception {
            if(CommonUtils.isNotNull(p)){
                FTPClient ftpClient = p.getObject();
                if (CommonUtils.isNotNull(ftpClient) && ftpClient.isConnected()) {
                    ftpClient.logout();
                    ftpClient.disconnect();
                }
            }
        }
    }
}
